package com.bjy.qa.agent.transport.database;

import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 数据库链接池
 */
public class PooledDataSource implements javax.sql.DataSource {
    private static final Logger logger = LoggerFactory.getLogger(PooledDataSource.class);

    private static final Map<String, javax.sql.DataSource> dataSourceMap = new ConcurrentHashMap<>(); // 数据源 map
    private String dataSourceKey; // 数据源 key，在 dataSourceMap 中用于区分不同的数据源

    private javax.sql.DataSource dataSource;

    private String driverClass; // 数据库驱动
    private String url; // 数据库连接字串
    private String username; // 数据库用户名
    private String password; // 数据库密码

    /**
     * 构造函数
     * @param driverClass 数据库驱动
     * @param url 数据库连接字串
     * @param username 数据库用户名
     * @param password 数据库密码
     */
    public PooledDataSource(String driverClass, String url, String username, String password) {
        this.driverClass = driverClass;
        this.url = url;
        this.username = username;
        this.password = password;
        this.dataSourceKey = String.format("%s::%s::%s", url, username, password);

        this.dataSource = getDataSource();
    }

    /**
     * 获取数据库数据源
     * @return
     */
    private javax.sql.DataSource getDataSource() {
        javax.sql.DataSource dataSource = (javax.sql.DataSource) dataSourceMap.get(this.dataSourceKey);
        if (dataSource == null) {
            dataSource = createDataSource();
            dataSourceMap.put(this.dataSourceKey, dataSource);
        }
        return dataSource;
    }

    /**
     * 创建数据源
     * @return
     */
    private javax.sql.DataSource createDataSource() {
        if (StringUtils.isBlank(this.driverClass)) {
            String message = String.format("数据库 driverClass 不能为空");
            logger.error(message);
            throw new RuntimeException(message);
        }
        if (StringUtils.isBlank(this.url)) {
            String message = String.format("数据库 连接字串url 不能为空");
            logger.error(message);
            throw new RuntimeException(message);
        }
        if (StringUtils.isBlank(this.username)) {
            String message = String.format("数据库 username 不能为空");
            logger.error(message);
            throw new RuntimeException(message);
        }
        if (StringUtils.isBlank(this.password)) {
            String message = String.format("数据库 password  不能为空");
            logger.error(message);
            throw new RuntimeException(message);
        }
        try {
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            logger.error("{} 数据库驱动不存在，请确保你在 pom 文件里引入了对应的依赖，或者确认你配置的驱动类名称是否正确", driverClass, e);
            throw new RuntimeException(String.format("数据库驱动 %s 不存在，请确保你在 pom 文件里引入了对应的依赖，或者确认你配置的驱动类名称是否正确", driverClass, e));
        }

        PoolConfiguration p = new PoolProperties();

        p.setValidationQuery("select 1");
        p.setTestOnBorrow(true);
        p.setTestWhileIdle(true);
        p.setFairQueue(false);
        p.setJmxEnabled(false);
        p.setTestOnReturn(false);
        p.setValidationInterval(30000L);
        p.setTimeBetweenEvictionRunsMillis(30000);
        p.setCommitOnReturn(true);
        p.setMinIdle(1);
        p.setMaxIdle(1);
        p.setMaxActive(40);
        p.setInitialSize(1);
        p.setMaxWait(10000);
        p.setRemoveAbandonedTimeout(10);
        p.setMinEvictableIdleTimeMillis(20000);
        p.setLogAbandoned(false);
        p.setRemoveAbandoned(false);
        p.setDriverClassName(driverClass);
        p.setUrl(url);
        p.setUsername(username);
        p.setPassword(password);
        org.apache.tomcat.jdbc.pool.DataSource datasource = null;
        datasource = new org.apache.tomcat.jdbc.pool.DataSource();
        datasource.setPoolProperties(p);
        return datasource;
    }

    public Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }

    public Connection getConnection(String s, String s2) throws SQLException {
        return this.dataSource.getConnection(s, s2);
    }

    public PrintWriter getLogWriter() throws SQLException {
        return this.dataSource.getLogWriter();
    }

    public void setLogWriter(PrintWriter printWriter) throws SQLException {
        this.dataSource.setLogWriter(printWriter);
    }

    public void setLoginTimeout(int i) throws SQLException {
        this.dataSource.setLoginTimeout(i);
    }

    public int getLoginTimeout() throws SQLException {
        return this.dataSource.getLoginTimeout();
    }

    @Override
    public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    public <T> T unwrap(Class<T> tClass) throws SQLException {
        return this.dataSource.unwrap(tClass);
    }

    public boolean isWrapperFor(Class<?> aClass) throws SQLException {
        return this.dataSource.isWrapperFor(aClass);
    }
}
